package org.smartboot.flow.core.builder;


import org.smartboot.flow.core.Condition;
import org.smartboot.flow.core.attribute.Attributes;
import org.smartboot.flow.core.component.Component;
import org.smartboot.flow.core.component.IfComponent;
import org.smartboot.flow.core.executable.Executable;
import org.smartboot.flow.core.util.AssertUtil;

/**
 * @author qinluo
 * @date 2022-11-11 11:40:20
 * @since 1.0.0
 */
public class IfComponentBuilder<T, S> extends ExecutableBuilder<T, S>{

    /**
     * Parent pipeline builder.
     */
    private final PipelineBuilder<T, S> pipelineBuilder;

    /**
     * This component's condition
     */
    private final Condition<T, S> condition;

    public IfComponentBuilder(Condition<T, S> condition) {
        this.pipelineBuilder = null;
        this.condition = condition;
    }

    public IfComponentBuilder(PipelineBuilder<T, S> engineBuilder, Condition<T, S> condition) {
        this.pipelineBuilder = engineBuilder;
        this.condition = condition;
    }

    @Override
    public IfComponentBuilder<T, S> apply(Attributes attributes, Object value) {
        super.apply(attributes, value);
        return this;
    }

    public PipelineBuilder<T, S> then(Component<T, S> component) {
        return this.then(component, null);
    }

    public PipelineBuilder<T, S> then(Component<T, S> component, Component<T, S> otherwise) {
        AssertUtil.notNull(pipelineBuilder, "Only pipeline's sub-builder call this method allowed");
        pipelineBuilder.next(this.build(component, otherwise));
        return pipelineBuilder;
    }

    public PipelineBuilder<T, S> then(Executable<T, S> executable) {
        Component<T, S> execute = super.asComponent(executable);
        return this.then(execute, null);
    }

    public PipelineBuilder<T, S> then(Executable<T, S> executable, Executable<T, S> otherwise) {
        Component<T, S> execute = super.asComponent(executable);
        Component<T, S> component = otherwise != null ? super.asComponent(otherwise) : null;
        return then(execute, component);
    }

    public Component<T, S> build(Component<T, S> component, Component<T, S> otherwise) {
        AssertUtil.notNull(component, "must not be null");
        IfComponent<T, S> ifComponent = new IfComponent<>(condition, component);
        ifComponent.setElseComponent(otherwise);
        applyValues(ifComponent);
        return ifComponent;
    }

    public Component<T, S> build(Component<T, S> component) {
        return this.build(component, null);
    }

    public Component<T, S> build(Executable<T, S> executable, Executable<T, S> otherwise) {
        Component<T, S> execute = super.asComponent(executable);
        Component<T, S> component = otherwise != null ? super.asComponent(otherwise) : null;
        return this.build(execute, component);
    }

    public Component<T, S> build(Executable<T, S> executable) {
        return this.build(executable, null);
    }
}
